home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1999 June
/
Macworld (1999-06).dmg
/
Shareware World
/
Info
/
For Developers
/
MacZoop2.0.sea
/
MacZoop2.0
/
Required Classes
/
ZWindowManager.cpp
< prev
next >
Wrap
Text File
|
1999-02-24
|
41KB
|
1,693 lines
/*************************************************************************************************
*
*
* MacZoop - "the framework for the rest of us"
*
*
*
* ZWindowManager.cpp -- desktop class handles floaters
*
*
*
*
*
* © 1996, Graham Cox
*
*
*
*
*************************************************************************************************/
#include "MacZoop.h"
#include "ZWindow.h"
#include "ZDialog.h"
#include "ZEventHandler.h"
#include "ProjectSettings.h"
#if _USE_DIR_POPUP
#include "DirectoryPopup.h"
#include "FinderObjects.h"
#endif
#if _WPOS_WINDOW_PLACEMENT
#include "ZResourceFile.h"
#endif
#include <dialogs.h>
ZWindowManager* gWindowManager = NULL;
/*--------------------------------*** CONSTRUCTOR ***---------------------------------*/
ZWindowManager::ZWindowManager()
: ZComrade()
{
// make the lists
FailNIL( nonFloaters = new ZWindowList());
FailNIL( floaters = new ZWindowList());
wmWindows = NULL;
wmMenu = NULL;
wmItemOffset = 0;
wmActive = TRUE;
wmDDDeactivated = FALSE;
SetRect( &fStoredZoom, 0, 0, 0, 0 );
fStoredZoomSource = fStoredZoom;
// set up member for controlling window placement
globalPlaceLoc.h = 2;
globalPlaceLoc.v = GetMBarHeight() + 2;
// we are the only one, and we are global
gWindowManager = this;
}
/*---------------------------------*** DESTRUCTOR ***---------------------------------*/
ZWindowManager::~ZWindowManager()
{
if ( nonFloaters )
{
nonFloaters->DisposeAll();
ForgetObject( nonFloaters );
}
if ( floaters )
{
floaters->DisposeAll();
ForgetObject( floaters );
}
if ( wmWindows )
ForgetObject( wmWindows );
}
/*---------------------------------*** ADDWINDOW ***----------------------------------*/
/*
add the window to the relevant list of windows, and set its initial (Z) position
----------------------------------------------------------------------------------------*/
void ZWindowManager::AddWindow( ZWindow* aWindow )
{
FailNILParam( aWindow );
ZWindow* zw = GetBottomFloater();
// determine if this window is a floater or not:
if ( aWindow->Floats())
{
BringBehind( aWindow, zw );
floaters->AppendItem( aWindow );
}
else
{
Boolean eligibleWindow;
eligibleWindow = ( ! IsDialog( aWindow )) ||
( IsDialog( aWindow ) && ! ((ZDialog*) aWindow )->IsModal());
// move behind the bottom floater unless this is a modal dialog
if ( eligibleWindow )
BringBehind( aWindow, zw );
nonFloaters->AppendItem( aWindow );
// if we're maintaining a "Windows" menu, append the window to our list if
// it non-floating and not a modal dialog box.
if ( wmWindows && eligibleWindow )
wmWindows->AppendItem( aWindow );
BuildWindowsMenu();
}
SendMessage( kWMMsgWindowAdded, aWindow );
}
/*--------------------------------*** REMOVEWINDOW ***--------------------------------*/
/*
remove the window from the relevant list; make sure the next window is activated correctly.
----------------------------------------------------------------------------------------*/
void ZWindowManager::RemoveWindow( ZWindow* aWindow )
{
FailNILParam( aWindow );
aWindow->Hide();
if ( aWindow->Floats())
floaters->DeleteObject( aWindow );
else
{
nonFloaters->DeleteObject( aWindow );
if ( wmWindows )
wmWindows->DeleteObject( aWindow );
// if all windows closed, reset global positioning variable
if ( CountWindows() == 0 )
{
globalPlaceLoc.h = 2;
globalPlaceLoc.v = GetMBarHeight() + 2;
}
}
SendMessage( kWMMsgWindowRemoved, aWindow );
}
/*-------------------------------*** INITIALLYPLACE ***-------------------------------*/
/*
Call this after creating a window to place it initially. By default, this will stack the
windows from top left towards bottom right, taking into account their correct title bar
heights, etc. Override for other behaviours. Floating windows are ignored by this method.
----------------------------------------------------------------------------------------*/
void ZWindowManager::InitiallyPlace( ZWindow* aWindow )
{
Rect wBorder;
short gh, gv;
FailNILParam( aWindow );
if ( ! aWindow->Floats())
{
aWindow->GetStructureFrameBorder( &wBorder );
gh = globalPlaceLoc.h + wBorder.left;
gv = globalPlaceLoc.v + wBorder.top;
aWindow->PlaceAt( gh, gv );
globalPlaceLoc.h += wBorder.left + 2;
globalPlaceLoc.v += wBorder.top + 2;
// if the bottom of the window falls off the screen, make it a bit less
// tall so that all its frame is visible.
RgnHandle wStruct;
short overHang;
GDHandle mainDev;
mainDev = GetMainDevice();
aWindow->GetStructureRegion( wStruct = NewRgn());
overHang = (*mainDev)->gdRect.bottom - (*wStruct)->rgnBBox.bottom;
// if overhang is negative, we've gone too far, so make the window smaller.
if ( overHang < 0 )
{
// only resize the window if it's a naturally resizable type, otherwise
// the user may end up with an unexpectedly nasty-looking window.
WindowPtr macWindow = aWindow->GetMacWindow();
short wType;
wType = GetWVariant( macWindow );
if ( wType == documentProc ||
wType == zoomDocProc )
{
wBorder = macWindow->portRect;
wBorder.bottom += overHang;
aWindow->SetSize( wBorder.right - wBorder.left, wBorder.bottom - wBorder.top - 2, FALSE );
}
// in any case the next window placed had better start back at the top...
globalPlaceLoc.v = GetMBarHeight() + 2;
globalPlaceLoc.h += 10;
}
DisposeRgn( wStruct );
}
}
/*---------------------------------*** HIDEWINDOW ***---------------------------------*/
/*
make the window invisible to the user. Does not change its front-to-back ordering unless
it was the top one in its layer, in which case the one below it is selected.
----------------------------------------------------------------------------------------*/
void ZWindowManager::HideWindow( ZWindow* aWindow )
{
FailNILParam( aWindow );
WindowPtr w = aWindow->GetMacWindow();
short i;
if ( w != NULL )
{
ShowHide( w, FALSE );
HiliteWindow( w, FALSE );
SendMessage( kWMMsgWindowHidden, aWindow );
}
// if this was the top window, select the next non-hidden one
if ( aWindow->Floats())
{
if ( aWindow == GetTopFloater() &&
floaters->CountItems() > 1 )
{
for( i = 2; i <= floaters->CountItems(); i++ )
{
aWindow = (ZWindow*) floaters->GetObject( i );
if ( aWindow && aWindow->IsVisible())
{
SelectWindow( aWindow );
break;
}
}
}
}
else
{
if ( aWindow == GetTopWindow())
{
if ( nonFloaters->CountItems() > 1 )
{
for( i = 2; i <= nonFloaters->CountItems(); i++ )
{
aWindow = (ZWindow*) nonFloaters->GetObject( i );
if ( aWindow && aWindow->IsVisible())
{
SelectWindow( aWindow );
break;
}
}
}
else
{
// the window being hidden is the only one. If a dialog,
// activate the floaters
if ( IsDialog( aWindow ))
Activate();
}
}
}
}
/*---------------------------------*** SHOWWINDOW ***---------------------------------*/
/*
make the window visible to the user. Does not change its front-to-back ordering
----------------------------------------------------------------------------------------*/
void ZWindowManager::ShowWindow( ZWindow* aWindow )
{
FailNILParam( aWindow );
if ( ! aWindow->IsVisible())
{
#if _ZOOM_RECT_FX
if ( gMacInfo.hasDragManager )
{
RgnHandle wStruct;
aWindow->GetStructureRegion( wStruct = NewRgn());
aWindow->zoomSource = gZoomFXSourceRect;
ZoomRects( &gZoomFXSourceRect, &(*wStruct)->rgnBBox, 10, kZoomAccelerate );
DisposeRgn( wStruct );
}
#endif
ShowHide( aWindow->GetMacWindow(), TRUE );
SendMessage( kWMMsgWindowShown, aWindow );
if ( aWindow == GetTopWindow() ||
aWindow == GetTopFloater())
SelectWindow( aWindow );
}
}
/*--------------------------------*** SELECTWINDOW ***--------------------------------*/
/*
make the window active. This handles the front-to-back ordering and creates the "floating"
window illusion.
----------------------------------------------------------------------------------------*/
void ZWindowManager::SelectWindow( ZWindow* aWindow )
{
FailNILParam( aWindow );
// this is where a certain amount of cunning comes in. To "Select" a non-floater, it
// is actually moved to come behind the bottom floater. Floaters are treated normally.
// Dialogs can come in front of all windows, though they will be set to non-floating.
ZWindow* zw;
long i;
if (! aWindow->IsVisible())
{
// if window hitherto has not been seen by the user, and the setting indicates we
// want the effect, perform the zoom open animation
#if _ZOOM_RECT_FX
if ( gMacInfo.hasDragManager )
{
RgnHandle wStruct;
aWindow->GetStructureRegion( wStruct = NewRgn());
aWindow->zoomSource = gZoomFXSourceRect;
ZoomRects( &gZoomFXSourceRect, &(*wStruct)->rgnBBox, 10, kZoomAccelerate );
DisposeRgn( wStruct );
}
#endif
}
// manipulate our lists and the mac window list
if ( aWindow->Floats())
{
i = floaters->FindIndex( aWindow );
// move to head of list, if not there already
if ( i > 1 )
{
// deactivate current "top"
zw = GetTopFloater();
if ( zw )
{
#if _ALL_FLOATERS_ACTIVE == OFF
HiliteWindow( zw->GetMacWindow(), FALSE );
#endif
zw->Deactivate();
SendMessage( kWMMsgFloaterDeactivated, zw );
}
floaters->MoveToFront( i );
BringBehind( aWindow, NULL );
}
// hilite and activate the new "top" window
// if window is not visible, make it so
ShowHide( aWindow->GetMacWindow(), TRUE );
aWindow->Activate();
HiliteWindow( aWindow->GetMacWindow(), TRUE );
SendMessage( kWMMsgFloaterActivated, aWindow );
}
else
{
i = nonFloaters->FindIndex( aWindow );
// if already on top, do nothing
if ( i > 1 )
{
// deactivate the current "top"
zw = GetTopWindow();
if ( zw )
PostActivation( zw, FALSE );
// move to head of list
nonFloaters->MoveToFront( i );
}
// bring window behind the bottom floater, unless it's a dialog, in which
// case it's put on top of everything
if ( IsDialog( aWindow ))
{
if ( wmActive )
Deactivate();
BringBehind( aWindow, NULL );
}
else
{
zw = GetBottomFloater();
BringBehind( aWindow, zw );
if ( ! wmActive )
Activate();
}
// hilite and activate the new "top" window
// if window is not visible, make it so
ShowHide( aWindow->GetMacWindow(), TRUE );
if ( ! aWindow->IsActive())
PostActivation( aWindow, TRUE );
}
}
/*-----------------------------*** DRAGWINDOWOUTLINE ***------------------------------*/
/*
drag the outline of the window and move it when the mouse is released. This replaces the
toolbox routine DragWindow, and in addition does a nicer job of clipping the outline.
----------------------------------------------------------------------------------------*/
void ZWindowManager::DragWindowOutline( ZWindow* aWindow, Point startPt, const short modifiers )
{
FailNILParam( aWindow );
// replaces the toolbox DragWindow, because that will bring a window to the front if
// you let it.
WindowPtr w;
RgnHandle dragRgn, temp = NULL;
Rect limitRect;
long dragOffset;
GrafPort screenPort;
GrafPtr savePort;
Point wPosition;
w = aWindow->GetMacWindow();
PauseCursorAnimation( 0 );
// if window frontmost and command key down, call command-click hook and return. The hook
// can be overridden to implement stuff such as popping up a directory path menu, etc.
if ( aWindow == GetTopWindow() &&
( modifiers & cmdKey ) == cmdKey )
{
// the hook returns a boolean to indicate whether processing should continue or not.
// If FALSE, we continue, otherwise we abort. The default hook method just returns FALSE
if ( CommandClickInFrontDragBar( aWindow, startPt ))
return;
}
// select the window if command key not down
#if _DRAGWINDOW_COMPATIBLE == OFF
if (( modifiers & cmdKey ) == 0 &&
aWindow != GetTopWindow() &&
aWindow != GetTopFloater())
{
SelectWindow( aWindow );
}
#if _UPDATE_ON_SELECT
aWindow->PerformUpdate();
#endif
#endif
// get the limit rect
limitRect = (*GetGrayRgn())->rgnBBox;
InsetRect( &limitRect, 4, 4 );
// get the outline to drag. This is simply a copy of the window's structure region
FailNIL( dragRgn = NewRgn());
CopyRgn(((WindowPeek) w)->strucRgn, dragRgn );
// set up a port in which to drag the outline. We do this to be good citizens,
// since meddling with the Mac's Window Manager port is tricky to get away with.
GetPort( &savePort );
OpenPort( &screenPort );
SetPort( &screenPort );
// make sure we can drag on the whole desktop
screenPort.portRect = (*GetGrayRgn())->rgnBBox;
SetClip( GetGrayRgn());
CopyRgn( screenPort.clipRgn, screenPort.visRgn );
// Remove the regions of all windows in front from the clip region, so it is clearer
// what will happen when the window moves.
FailNIL( temp = NewRgn());
CalcWindowRgns( aWindow, temp );
DiffRgn( screenPort.clipRgn, temp, screenPort.clipRgn );
// if we have system 8.0 or later, use a 2-pixel gray drag region, not a 1-pixel
if ( gMacInfo.systemVersion >= 0x0800 )
{
CopyRgn( dragRgn, gUtilRgn );
InsetRgn( gUtilRgn, 2, 2 );
DiffRgn( dragRgn, gUtilRgn, dragRgn );
}
// the mouse may have moved away from the startPt already, since the update may have taken
// a while. In order to prevent the window jumping in this situation, we just check that the
// mouse is still in fact, down!
if ( StillDown())
dragOffset = DragGrayRgn( dragRgn, startPt, &limitRect, &limitRect, noConstraint, NULL );
else
dragOffset = kMouseUpOutOfSlop;
// delete our port
ClosePort( &screenPort );
SetPort( savePort );
// check the window drag wasn't bogus:
if ( dragOffset != kMouseUpOutOfSlop )
{
// OK, figure out where the window moved to, and move it there. If the command key
// is not down, select tha' booga!
SetPort( w );
wPosition = topLeft( w->portRect );
LocalToGlobal( &wPosition );
SetPort( savePort );
// if we are exactly compatible with toolbox DragWindow(), then select the window here
#if _DRAGWINDOW_COMPATIBLE
if (( modifiers & cmdKey ) == 0 &&
aWindow != GetTopWindow() &&
aWindow != GetTopFloater())
SelectWindow( aWindow );
#endif
MoveWindow( w, wPosition.h + LoWord( dragOffset ), wPosition.v + HiWord( dragOffset ), FALSE );
SendMessage( kWMMsgWindowMoved, aWindow );
}
// clean up
DisposeRgn( dragRgn );
if ( temp )
DisposeRgn( temp );
ResumeCursorAnimation();
}
/*-----------------------------------*** SUSPEND ***----------------------------------*/
/*
application is suspending- hide the floaters
----------------------------------------------------------------------------------------*/
void ZWindowManager::Suspend()
{
// the application is being suspended, so all floaters should be hidden
ZWindow *aFloater, *tw;
short i;
for (i = 1; i <= floaters->CountItems(); i++)
{
aFloater = (ZWindow*) floaters->GetObject( i );
if ( aFloater )
ShowHideFloater( aFloater, TRUE );
}
tw = GetTopWindow();
if ( tw )
PostActivation( tw, FALSE );
}
/*-----------------------------------*** RESUME ***-----------------------------------*/
/*
application is resuming- show the floaters
----------------------------------------------------------------------------------------*/
void ZWindowManager::Resume()
{
// the application is being resumed, so all floaters should be re-shown.
ZWindow *aFloater, *tw;
short i;
for (i = 1; i <= floaters->CountItems(); i++)
{
aFloater = (ZWindow*) floaters->GetObject( i );
if ( aFloater )
ShowHideFloater( aFloater, FALSE );
}
tw = GetTopWindow();
if ( tw )
PostActivation( tw, TRUE );
}
/*---------------------------------*** DEACTIVATE ***---------------------------------*/
/*
a modal dialog is coming up, so deactivate all floaters. This is called for you when
necessary. If you are displaying a non-MacZoop dialog (Standard File, etc) you should
use DeactivateForDialog() instead.
----------------------------------------------------------------------------------------*/
void ZWindowManager::Deactivate()
{
// a dialog is up, so all floaters plus the top window must be deactivated
ZWindow* zw;
#if _ALL_FLOATERS_ACTIVE == OFF
zw = GetTopFloater();
if ( zw )
PostActivation( zw, FALSE );
#else
short i;
for (i = 1; i <= floaters->CountItems(); i++ )
{
zw = (ZWindow*) floaters->GetObject( i );
if ( zw )
PostActivation( zw, FALSE );
}
#endif
wmActive = FALSE;
}
/*----------------------------*** DEACTIVATEFORDIALOG ***-----------------------------*/
/*
in order to support nice zoom rects when non-MacZoop dialogs are displayed, this method
can be called instead of Deactivate to provide the animation by proxy for the dialog.
This should ONLY be called for dialogs and alerts that are not ZDialog objects.
----------------------------------------------------------------------------------------*/
void ZWindowManager::DeactivateForDialog( short dlogID, Boolean isAlert )
{
ZWindow* zw;
Deactivate();
zw = GetTopWindow();
if ( zw )
{
PostActivation( zw, FALSE );
wmDDDeactivated = TRUE;
zw->PerformUpdate();
}
SendMessage( kWMMsgMacDialogUp, NULL );
#if _ZOOM_RECT_FX
// in order to display the animation by proxy for the dialog we are about to put
// up, we need to obtain the dialog's window frame by taking a peek into the
// dialog record
if ( gMacInfo.hasDragManager && ( dlogID != -1 ))
{
Rect r;
AlertTHndl atH;
DialogTHndl dtH;
if ( isAlert )
{
atH = (AlertTHndl) GetResource( 'ALRT', dlogID );
if ( atH )
{
r = (*atH)->boundsRect;
ReleaseResource((Handle) atH );
}
}
else
{
dtH = (DialogTHndl) GetResource( 'DLOG', dlogID );
if ( dtH )
{
r = (*dtH)->boundsRect;
ReleaseResource((Handle) dtH );
}
}
// we are going to need to assume that the dialog/alert is going to be placed on the screen
// in the standard alert position (for now- there are ways to be more intelligent about this)
// so we have to compute that location:
Rect screen = qd.screenBits.bounds;
screen.top += GetMBarHeight();
short topSpace = screen.bottom - screen.top - r.bottom - r.top;
short leftSpace = screen.right - screen.left - r.right - r.left;
OffsetRect( &r, ( leftSpace / 2 ) - r.left, ( topSpace / 4 ) - r.top );
// that's the one- do the animation
ZoomRects( &gZoomFXSourceRect, &r, 10, kZoomAccelerate );
// store the rects on behalf of the dialog/alert so we can do the reverse animation
// when we are reactivated
fStoredZoomSource = gZoomFXSourceRect;
fStoredZoom = r;
}
#endif
}
/*----------------------------------*** ACTIVATE ***----------------------------------*/
/*
the modal dialog is going away, so reactivate the floaters and top window
----------------------------------------------------------------------------------------*/
void ZWindowManager::Activate()
{
// a dialog is going away, so all floaters plus the top window must be reactivated
SendMessage( kWMMsgMacDialogDown, NULL );
ZWindow* zw;
if ( wmDDDeactivated )
{
zw = GetTopWindow();
if ( zw )
PostActivation( zw, TRUE );
wmDDDeactivated = FALSE;
}
#if _ALL_FLOATERS_ACTIVE == OFF
zw = GetTopFloater();
if ( zw )
PostActivation( zw, TRUE );
#else
short i;
for (i = 1; i <= floaters->CountItems(); i++ )
{
zw = (ZWindow*) floaters->GetObject( i );
if ( zw )
PostActivation( zw, TRUE );
}
#endif
// if we have a stored zoom, zoom down from it.
#if _ZOOM_RECT_FX
if ( ! EmptyRect( &fStoredZoom ) && gMacInfo.hasDragManager )
{
ZoomRects( &fStoredZoom, &fStoredZoomSource, 10, kZoomDecelerate );
SetRect( &fStoredZoom, 0, 0, 0, 0 );
fStoredZoomSource = fStoredZoom;
}
#endif
wmActive = TRUE;
}
/*--------------------------------*** GETTOPWINDOW ***--------------------------------*/
/*
get uppermost non-floating window
----------------------------------------------------------------------------------------*/
ZWindow* ZWindowManager::GetTopWindow()
{
// returns the top non-floating window
if ( nonFloaters->CountItems() > 0 )
return (ZWindow*) nonFloaters->GetObject( 1 );
else
return NULL;
}
/*-------------------------------*** GETTOPFLOATER ***--------------------------------*/
/*
get uppermost floating window
----------------------------------------------------------------------------------------*/
ZWindow* ZWindowManager::GetTopFloater()
{
// returns the top floating window (even if not visible)
if ( floaters->CountItems() > 0 )
return (ZWindow*) floaters->GetObject( 1 );
else
return NULL;
}
/*------------------------------*** GETBOTTOMFLOATER ***------------------------------*/
/*
get the last window in the floating layer. Top window is the one behind this.
----------------------------------------------------------------------------------------*/
ZWindow* ZWindowManager::GetBottomFloater()
{
// returns the bottom-most VISIBLE floater
long fCount = floaters->CountItems();
if ( fCount > 0 )
{
ZWindow* botFloater;
// iterate through the list of floaters looking for the bottom-most visible one.
// Iterate in reverse order to facilitate finding the bottom one.
while( fCount )
{
botFloater = (ZWindow*) floaters->GetObject( fCount-- );
if ( botFloater->IsVisible())
break;
else
botFloater = NULL;
}
return botFloater;
}
else
return NULL;
}
/*------------------------------*** MOVEWINDOWBEHIND ***------------------------------*/
/*
move <aWindow> behind <behindWindow>. If NULL, moves it behind all others. Works for
floaters too, within their layer.
----------------------------------------------------------------------------------------*/
void ZWindowManager::MoveWindowBehind( ZWindow* aWindow, ZWindow* behindWindow )
{
FailNILParam( aWindow );
long wIndex, nIndex;
Boolean wasActive = FALSE;
if ( aWindow->Floats())
{
if ( behindWindow != NULL )
{
if ( ! behindWindow->Floats())
behindWindow = GetBottomFloater();
}
else
behindWindow = GetBottomFloater();
// manipulate our list
wIndex = floaters->FindIndex( aWindow );
nIndex = floaters->FindIndex( behindWindow );
floaters->MoveItem( wIndex, nIndex );
}
else
{
if ( behindWindow == NULL )
behindWindow = (ZWindow*) nonFloaters->GetObject( nonFloaters->CountItems());
wasActive = aWindow->IsActive();
wIndex = nonFloaters->FindIndex( aWindow );
nIndex = nonFloaters->FindIndex( behindWindow );
nonFloaters->MoveItem( wIndex, nIndex );
}
BringBehind( aWindow, behindWindow );
if ( wasActive )
{
PostActivation( aWindow, FALSE );
SelectWindow( GetTopWindow());
}
}
/*------------------------------*** CHECKDIALOGEVENT ***------------------------------*/
/*
determine if the event is aimed at a dialog. This replaces the toolbox IsDialogEvent call
such that it does not call FrontWindow().
----------------------------------------------------------------------------------------*/
Boolean ZWindowManager::CheckDialogEvent( EventRecord* theEvent )
{
// the event is for a dialog if the window kind explicitly passed with certain events is
// a dialog, or for other events, that the top window as we know it is a dialog.
WindowPeek w;
Boolean result = FALSE;
ZWindow* zw;
// is this a window explicit event?
if ( theEvent->what == updateEvt ||
theEvent->what == activateEvt )
{
// yes, so get the window and see if it's a dialog
w = (WindowPeek) theEvent->message;
result = ( w->windowKind == dialogKind );
}
else
{
// is the event a mouse down? If so we need to see if it was in the active dialog
// window.
if ( theEvent->what == mouseDown )
{
short part = FindWindow( theEvent->where, (WindowPtr*) &w );
zw = GetTopWindow();
result = ( part == inContent &&
w->windowKind == dialogKind &&
zw &&
zw->GetMacWindow() == (WindowPtr) w );
}
else
{
zw = GetTopWindow();
// we do our own checks but also call the toolbox IsDialogEvent, so that
// ballon help in dialogs is correctly displayed. (Balloon help hooks into
// this routine to provide dialog balloons).
result = ( zw &&
((WindowPeek) zw->GetMacWindow())->windowKind == dialogKind &&
( theEvent->what == keyDown ||
theEvent->what == autoKey ||
IsDialogEvent( theEvent )));
}
}
return result;
}
/*--------------------------------*** LOCATEWINDOW ***--------------------------------*/
/*
find the window under the mouse, or NULL if none are
----------------------------------------------------------------------------------------*/
ZWindow* ZWindowManager::LocateWindow( const Point globalMouse )
{
WindowPeek w;
ZWindow* zw = NULL;
w = ( WindowPeek ) FrontWindow();
while ( w )
{
if ( PtInRgn( globalMouse, w->strucRgn ))
{
zw = GetZWindow(( WindowPtr ) w );
break;
}
w = w->nextWindow;
}
return zw;
}
/*--------------------------------*** GETNTHWINDOW ***--------------------------------*/
/*
return the window <n>, or NULL if bad index
----------------------------------------------------------------------------------------*/
ZWindow* ZWindowManager::GetNthWindow( const long n )
{
ZWindow* zw = NULL;
try
{
zw = (ZWindow*) nonFloaters->GetObject( n );
}
catch( OSErr err )
{
}
return zw;
}
/*--------------------------------*** GETNTHFLOATER ***-------------------------------*/
/*
return the floating window <n>, or NULL if bad index
----------------------------------------------------------------------------------------*/
ZWindow* ZWindowManager::GetNthFloater( const long n )
{
ZWindow* zw = NULL;
try
{
zw = (ZWindow*) floaters->GetObject( n );
}
catch( OSErr err )
{
}
return zw;
}
/*----------------------------------*** ISDIALOG ***----------------------------------*/
/*
is the window a modal dialog?
----------------------------------------------------------------------------------------*/
Boolean ZWindowManager::IsDialog( ZWindow* aWindow )
{
// return TRUE if the window is a modal dialog (but not for modeless ones)
if ( aWindow )
{
ZDialog* zd = dynamic_cast<ZDialog*> ( aWindow );
if (zd && zd->IsModal())
return TRUE;
else
return FALSE;
}
else
return FALSE;
}
/*--------------------------*** GETUNIQUEUNTITLEDNAME ***-----------------------------*/
/*
as part of the human interface guidelines adherence, we automatically name new windows
untitled, untitled 1, etc. This method scans through the names of all the windows in the
main list (ignores floaters), making sure the name is unique. If not, it appends 1, 2, etc
until the name is unique. If the name was unique, it returns FALSE, otherwise TRUE. i.e.
TRUE means we modified the name. Uses EqualString to compare names, ignores case.
----------------------------------------------------------------------------------------*/
Boolean ZWindowManager::GetUniqueUntitledName( Str255 wName )
{
short n = 1, i;
Boolean result = FALSE, match;
Str255 sName, temp;
ZWindow* zw;
CopyPString( wName, temp );
do
{
match = FALSE;
for ( i = 1; i <= nonFloaters->CountItems(); i++ )
{
zw = (ZWindow*) nonFloaters->GetObject( i );
zw->GetName( sName );
if ( EqualString( temp, sName, FALSE, FALSE ))
{
match = TRUE;
break;
}
}
if ( match )
{
// the name matched some window, so append a digit and try again
CopyPString( wName, temp );
NumToString( n++, sName );
ConcatPStrings( temp, "\p " );
ConcatPStrings( temp, sName );
}
else
{
result = TRUE;
CopyPString( temp, wName );
}
}
while( ! result );
return result;
}
/*----------------------------------*** FLOATIDLE ***---------------------------------*/
/*
pass idle to each floater, in case they do periodic action
----------------------------------------------------------------------------------------*/
void ZWindowManager::FloatIdle()
{
long i;
ZWindow* aFloater;
for( i = 1; i <= floaters->CountItems(); i++ )
{
aFloater = (ZWindow*) floaters->GetObject( i );
if ( aFloater )
aFloater->GetHandler()->Idle();
}
}
/*---------------------------------*** COUNTWINDOWS ***-------------------------------*/
/*
return the number of non-floating windows the manager knows about
----------------------------------------------------------------------------------------*/
short ZWindowManager::CountWindows()
{
return nonFloaters->CountItems();
}
/*---------------------------------*** COUNTFLOATERS ***------------------------------*/
/*
return the number of floating windows the manager knows about
----------------------------------------------------------------------------------------*/
short ZWindowManager::CountFloaters()
{
return floaters->CountItems();
}
/*--------------------------------*** SETWINDOWSMENU ***------------------------------*/
/*
sets the passed menu to be the application's "Windows" menu. Called by ZMenuBar- do not
call this method directly- use gMenuBar->NominateWindowsMenu() instead. This should be
called before any non-floating windows are created.
----------------------------------------------------------------------------------------*/
void ZWindowManager::SetWindowsMenu( MenuHandle aMenu )
{
FailNILParam( aMenu );
wmMenu = aMenu;
wmItemOffset = CountMenuItems( aMenu );
// make a list to keep an ordered list of windows that does not depend on
// the front-to-back order
FailNIL( wmWindows = new ZWindowList());
BuildWindowsMenu();
}
/*-----------------------------*** SELECTWINDOWFROMMENU ***---------------------------*/
/*
called only by the main menubar to select the window from the menu. Do not call this
yourself.
----------------------------------------------------------------------------------------*/
void ZWindowManager::SelectWindowFromMenu( const short itemID )
{
if ( wmMenu && wmWindows && !IsDialog( GetTopWindow()))
{
short n = itemID - wmItemOffset;
if ( wmItemOffset > 0 )
n--; // allow for divider line
if (( n > 0 ) && ( n <= wmWindows->CountItems()))
{
ZWindow* zw = (ZWindow*) wmWindows->GetObject( n );
if ( zw )
zw->Select();
}
}
}
/*-------------------------------*** ZOOMWINDOWCLOSED ***-----------------------------*/
/*
called when a window is closed to perform the "zoom closed" animation, if this effect
is enabled.
----------------------------------------------------------------------------------------*/
void ZWindowManager::ZoomWindowClosed( ZWindow* aWindow )
{
#if _ZOOM_RECT_FX
if ( gMacInfo.hasDragManager && ( gApplication->GetPhase() == kRunning ))
{
RgnHandle wStruct;
aWindow->GetStructureRegion( wStruct = NewRgn());
ZoomRects( &(*wStruct)->rgnBBox, &aWindow->zoomSource, 10, kZoomDecelerate );
DisposeRgn( wStruct );
}
#endif
}
Boolean ZWindowManager::CommandClickInFrontDragBar( ZWindow* target, const Point startPt )
{
#if _USE_DIR_POPUP
// if we're using the directory pop-up code, call that here.
// has the window got a file?
FSSpec ffs;
Boolean result;
target->GetFileSpec( &ffs );
if ( ffs.vRefNum != kNoFile )
{
// we have a spec, so do that menu tracking thang, courtesy of Marco Piovanelli...
result = TrackDirectoryPopup( &ffs, target->GetMacWindow(), startPt );
if ( result )
{
// ffs now contains spec of selected directory, so we now assemble
// an apple event to tell the Finder to open it.
FailOSErr( OpenFinderObject( &ffs ));
}
else
result = ! StillDown();
return result;
}
else
return FALSE;
#else
return FALSE;
#endif
}
short ZWindowManager::SaveWindowPosition( ZWindow* aWindow, ZResourceFile* aFile, short id )
{
#if _WPOS_WINDOW_PLACEMENT
WPosHdl wpH;
ZResourceFile* st;
Rect pr;
short x, y;
FailNILParam( aWindow );
// if <aFile> is NULL, use gPrefsFile if it exists. Otherwise do nothing.
if ( aFile == NULL )
st = (ZResourceFile*) gPrefsFile;
else
st = aFile;
if ( st == NULL )
return 0;
FailNIL( wpH = ( WPosHdl ) NewHandleClear( sizeof( WPosResource )));
aWindow->GetGlobalPosition( &x, &y );
pr = aWindow->GetMacWindow()->portRect;
(*wpH)->globalH = x;
(*wpH)->globalV = y;
(*wpH)->width = pr.right - pr.left;
(*wpH)->height = pr.bottom - pr.top;
if ( id == 0 )
id = _UNIQUE_ID;
// make sure the resource fork is open, etc. In general the file should already exist-
// this will create it if not, but you'll have more control if you deal with this.
if ( ! st->IsReal() || ! st->HasResFork())
st->CreateResFork();
short rf = st->GetResourceRefNumber();
try
{
st->OpenResFork();
st->WriteResource((Handle) wpH, kWindowPosResType, id );
ReleaseResource((Handle) wpH );
if ( rf == _NOT_OPEN )
st->CloseResFork();
}
catch( OSErr err )
{
if ( rf == _NOT_OPEN )
st->CloseResFork();
// don't propagate- not important.
}
#endif
// return the ID we actually used: (TO DO)
return 0;
}
void ZWindowManager::RestoreWindowPosition( ZWindow* aWindow, ZResourceFile* aFile, const short id )
{
#if _WPOS_WINDOW_PLACEMENT
WPosHdl wpH;
ZResourceFile* st;
Rect pr;
FailNILParam( aWindow );
// if <aFile> is NULL, use gPrefsFile if it exists. Otherwise do nothing.
if ( aFile == NULL )
st = (ZResourceFile*) gPrefsFile;
else
st = aFile;
if ( st == NULL )
return;
// detach & read the pos resource, if any.
short rf = st->GetResourceRefNumber();
try
{
st->OpenResFork();
wpH = (WPosHdl) st->ReadResource( kWindowPosResType, id );
if ( wpH )
{
// build the potential global rect of the window, to see if it's going to be on screen.
// Note that under System 8.0+, the window frame can be dragged by its edges, but on
// earlier systems only the title bar is draggable. We must check that a DRAGGABLE part of
// the window is visible before moving it to that location.
SetRect( &pr, 0, 0, (*wpH)->width, (*wpH)->height );
OffsetRect( &pr, (*wpH)->globalH, (*wpH)->globalV );
short tBar = aWindow->GetTitleBarHeight();
pr.top -= tBar;
// modify rect according to titlebar height, and system, etc
if ( gMacInfo.systemVersion < 0x0800 )
pr.bottom = pr.top + tBar;
// if on screen, move the window. Otherwise leave it where it is:
if ( WindowOnDesktop( &pr ))
aWindow->PlaceAt((*wpH)->globalH, (*wpH)->globalV );
ReleaseResource((Handle) wpH );
}
if ( rf == _NOT_OPEN )
st->CloseResFork();
}
catch( OSErr err )
{
if ( rf == _NOT_OPEN )
st->CloseResFork();
// don't propagate- it's not serious if this fails.
}
#endif
}
#pragma mark -
/*---------------------------------*** BRINGBEHIND ***--------------------------------*/
/*
change the window ordering so it is behind another. If behindWindow is NULL, window is
brought to the front.
----------------------------------------------------------------------------------------*/
void ZWindowManager::BringBehind( ZWindow* aWindow, ZWindow* behindWindow )
{
// brings <aWindow> behind <behindWindow>. If <behindWindow> is NULL, it is brought
// to the front. This manipulates the mac windowlist to match the state here.
WindowPtr a, b;
if ( aWindow == behindWindow )
return;
if ( behindWindow )
{
a = aWindow->GetMacWindow();
b = behindWindow->GetMacWindow();
SendBehind( a, b );
}
else
BringToFront( aWindow->GetMacWindow());
}
/*-------------------------------*** POSTACTIVATION ***-------------------------------*/
/*
simulate an activation event for the window
----------------------------------------------------------------------------------------*/
void ZWindowManager::PostActivation( ZWindow* aWindow, Boolean state )
{
// posts an activate event for the window. This will be picked up by the event handler, which
// will then maintain the command chain correctly. Floater activations are never sent in this
// way, but their activate methods are called directly.
if ( aWindow->IsVisible())
{
HiliteWindow( aWindow->GetMacWindow(), state );
if ( aWindow->Floats())
{
if ( state )
aWindow->Activate();
else
aWindow->Deactivate();
}
else
{
#if _ACTIVATE_EVENTS_ARE_REAL
EvQElPtr evQ;
if ( aWindow )
{
long evtMessage = (long) aWindow->GetMacWindow();
FailOSErr( PPostEvent( activateEvt, evtMessage, &evQ ));
// set up the modifiers to indicate activation state
if ( state )
evQ->evtQModifiers |= activeFlag;
else
evQ->evtQModifiers &= ~activeFlag;
}
#else
ZEventHandler* ze = gApplication->GetEventHandler();
ze->HandleWindowActivate( aWindow->GetMacWindow(), state );
#endif
SendMessage( state? kWMMsgWindowActivated : kWMMsgWindowDeactivated, aWindow );
}
}
}
/*------------------------------*** CALCWINDOWRGNS ***-------------------------------*/
/*
calculate the union of the window structure regions in front of the window. This is used
to build a clip region for window dragging.
----------------------------------------------------------------------------------------*/
void ZWindowManager::CalcWindowRgns( ZWindow* aWindow, RgnHandle aRgn )
{
// sets <theRgn> to the union of all windows in front if <aWindow>, including floaters.
// This is used to form the clip region for a window drag. Note- this doesn't check the
// parameters for sanity.
SetEmptyRgn( aRgn );
// the simplest way to achieve this is to scan the real mac window list, since that
// allows us to treat the window ordering simply without consideration of our separate
// lists.
WindowPeek w = (WindowPeek) FrontWindow();
while (w && w != (WindowPeek) aWindow->GetMacWindow())
{
UnionRgn( w->strucRgn, aRgn, aRgn );
w = w->nextWindow;
}
}
/*------------------------------*** SHOWHIDEFLOATER ***-------------------------------*/
/*
show or hide a floater by moving it offscreen.
----------------------------------------------------------------------------------------*/
void ZWindowManager::ShowHideFloater( ZWindow* aFloater, Boolean hide )
{
FailNILParam( aFloater );
short dh = 10000;
Point wLoc;
WindowPtr w = aFloater->GetMacWindow();
Rect dtBounds = (*GetGrayRgn())->rgnBBox;
if (! hide)
dh = -dh;
wLoc = topLeft( w->portRect );
aFloater->Focus();
LocalToGlobal( &wLoc );
// don't attempt to hide or show more than once- it doesn't work. To this end we check
// that the window is not already positioned
if (( hide && wLoc.h < dtBounds.right ) ||
( ! hide && wLoc.h > dtBounds.right ))
MoveWindow( w, wLoc.h + dh, wLoc.v, FALSE );
}
/*-----------------------------*** BUILDWINDOWSMENU ***-------------------------------*/
/*
fill menu with current list of windows, and check current one.
----------------------------------------------------------------------------------------*/
void ZWindowManager::BuildWindowsMenu()
{
short n, i, mi;
if ( wmMenu )
{
// delete items beyond initial number
n = CountMenuItems( wmMenu );
while( n > wmItemOffset )
DeleteMenuItem( wmMenu, n-- );
// set menu to window titles. If the offset was >0, add a dividing line first
if ( wmWindows )
{
ZWindow* zw;
Str255 title;
n = wmWindows->CountItems();
if (( wmItemOffset > 0 ) && ( n > 0 ))
AppendMenu( wmMenu, "\p-" );
for( i = 1; i <= n; i++ )
{
mi = i + wmItemOffset;
if ( wmItemOffset > 0 )
mi++; // allow for extra divider line
zw = (ZWindow*) wmWindows->GetObject( i );
zw->GetName( title );
AppendMenu( wmMenu, "\px(" );
SetMenuItemText( wmMenu, mi, title );
#if _ENUMERATE_WM_CMDS
if ( i < 11 )
SetItemCmd( wmMenu, mi, i + 0x2F );
#endif
if ( ! IsDialog( GetTopWindow()))
EnableItem( wmMenu, mi );
// if window is active, check that item
if ( zw == GetTopWindow())
CheckItem( wmMenu, mi, TRUE );
}
}
}
}
Boolean ZWindowManager::WindowOnDesktop( Rect* wFrame )
{
// return TRUE if the rect passed intersects the desktop. Called by RestoreWindowPosition
// to see if the restored position is legal on this system.
RectRgn( gUtilRgn, wFrame );
SectRgn( gUtilRgn, GetGrayRgn(), gUtilRgn );
return ( ! EmptyRgn( gUtilRgn ));
}